
/*
 *
 *  * Copyright (c) 2016. For Intelligent Group.
 *
 */
package com.intelligent.ispc.client.ex.dynamictable;

import com.intelligent.ispc.client.utils.GBC;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;

/**
 * Created by Ethan.Yang on 16/10/21.
 */
public class DyTablePanel extends JPanel {

    private DyTableLoader tableLoader;
    private boolean enable = true;
    private int maximum;

    /**
     * Constructor.
     *
     * @param tableLoader loader.
     */
    public DyTablePanel(DyTableLoader tableLoader) {
        this.tableLoader = tableLoader;
        initComponents();
    }

    /**
     * Initialization of components,
     * initialization of fixed columns,
     * as well as set up a vertical scroll bar or horizontal scroll bar of the listener
     */
    public void initComponents() {
        final int weightx = 100;
        final int weighty = 100;
        dataTable = new JTable();
        if (tableLoader.getFixedColSize() > 0) {
            fixedTable = new JTable(tableLoader.getFixedModel());
            fixedTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            fixedTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            fixedTable.getSelectionModel().addListSelectionListener(
                    new ListSelectionListener() {
                        public void valueChanged(ListSelectionEvent arg0) {
                            checkSelection(true);

                        }
                    });

            dataTable.getSelectionModel().addListSelectionListener(
                    new ListSelectionListener() {
                        public void valueChanged(ListSelectionEvent arg0) {
                            checkSelection(false);
                        }
                    });

            dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            dataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            viewport = new JViewport();
            viewport.setView(fixedTable);
            viewport.setPreferredSize(fixedTable.getPreferredSize());
            componentsEvent();

            scroll = new JScrollPane(dataTable);
            scroll.setRowHeaderView(viewport);
            scroll.setCorner(JScrollPane.UPPER_LEFT_CORNER, fixedTable.getTableHeader());

        } else {
            dataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            scroll = new JScrollPane(dataTable);
            scroll.setViewportView(dataTable);
        }
        if (tableLoader.getFlag() == DyTableLoader.ROW) {
            scroll.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
                @Override
                public void adjustmentValueChanged(AdjustmentEvent e) {
                    if (enable) {
                        if (tableLoader != null) {
                            JScrollBar bar = (JScrollBar) e.getSource();
                            int max = bar.getMaximum();
                            int extent = bar.getModel().getExtent();
                            int value = bar.getValue();
                            final int vDistance = 10;
                            if ((max - (value + extent)) < vDistance && value != 0 && tableLoader.getPageNumber() != tableLoader.getPageCount()) {
                                scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                                new NextTask().execute();
                            } else if (value < vDistance && tableLoader.getPageNumber() > 1) {
                                scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                                new PreTask().execute();
                            }
                        }
                    }

                }
            });
        } else if (tableLoader.getFlag() == DyTableLoader.COL) {
            scroll.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
                @Override
                public void adjustmentValueChanged(AdjustmentEvent e) {
                    if (enable) {
                        if (tableLoader != null) {
                            JScrollBar bar = (JScrollBar) e.getSource();
                            int max = bar.getMaximum();
                            int extent = bar.getModel().getExtent();
                            int value = bar.getValue();
                            final double hDistance = 0.001;
                            if ((max - (value + extent)) < hDistance && max - extent > hDistance && value != 0 && tableLoader.getPageNumber() != tableLoader.getPageCount()) {
                                scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                                new NextTask().execute();

                            } else if (value < hDistance && tableLoader.getPageNumber() > 1) {
                                scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                                new PreTask().execute();
                            }

                        }
                    }
                }
            });
        }
        this.setLayout(new GridBagLayout());
        this.add(scroll, new GBC(0, 0).setFill(GBC.BOTH).setWeight(weightx, weighty));
    }

    /**
     * Table adaptive method, the need to initialize the table,
     * after the parent container size changes and the table model is modified
     *
     * @param bool Whether the interface has been displayed
     */
    public void allResizeTable(boolean bool) {
        Dimension containerWidth = null;
        if (!bool) {
            containerWidth = scroll.getPreferredSize();
        } else {
            containerWidth = scroll.getSize();
        }
        int allWidth = dataTable.getIntercellSpacing().width;
        maximum = 0;
        final int widthPlus = 20;
        for (int j = 0; j < dataTable.getColumnCount(); j++) {
            int maxNum = 0;
            //Find the maximum cell for each column
            for (int i = 0; i < dataTable.getRowCount(); i++) {
                int width = dataTable.
                        getCellRenderer(i, j).getTableCellRendererComponent(
                        dataTable, dataTable.getValueAt(i, j), false,
                        false, i, j).getPreferredSize().width;
                if (width > maxNum) {
                    maxNum = width;
                }
            }
            maxNum += widthPlus;
            dataTable.getColumnModel().
                    getColumn(j).setPreferredWidth(maxNum);
            maximum += maxNum;
            allWidth += maxNum + dataTable.getIntercellSpacing().width;
        }
        allWidth += dataTable.getIntercellSpacing().width;
        if (tableLoader.getFixedColSize() > 0) {
            allWidth += fixedTable.getWidth();
        }
        if (allWidth > containerWidth.width) {
            dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
        } else {
            dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS);
        }
    }

    /**
     * Load data into tables
     */
    public void loadData() {
        JScrollBar bar = (JScrollBar) scroll.getVerticalScrollBar();
        if (tableLoader.getFlag() == DyTableLoader.COL) {
            bar = (JScrollBar) scroll.getHorizontalScrollBar();
        }
        bar.setValue(0);
        tableLoader.initBatch();
        dataTable.setModel(tableLoader.getNormalModel());
        if (tableLoader.getFixedColSize() > 0) {
            fixedTable.setModel(tableLoader.getFixedModel());
        }
        fixScrollUI();
    }

    /**
     * Refresh table data
     */
    public void clearAndRefreshTables() {
        tableLoader.resetProperties();
        if (fixedTable != null) {
            fixedTable.updateUI();
        }

        if (dataTable != null) {
            dataTable.updateUI();
        }

        scroll.updateUI();
    }

    public DyTableLoader getTableLoader() {
        return tableLoader;
    }

    public void setTableLoader(DyTableLoader tableLoader) {
        this.tableLoader = tableLoader;
    }

    /*
    Change the width of the fixed column triggering event
     to initialize the size of the viewPort
     */
    private void componentsEvent() {
        viewport.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                int width = fixedTable.getWidth();
                int height = fixedTable.getHeight();
                viewport.setPreferredSize(new Dimension(width, height));
                allResizeTable(true);
            }
        });
    }

    /*
     * Select a column, synchronize the fixed column and dynamic column highlighted
     */
    private void checkSelection(boolean isFixedTable) {
        int fixedSelectedIndex = fixedTable.getSelectedRow();
        int selectedIndex = dataTable.getSelectedRow();
        if (fixedSelectedIndex != selectedIndex) {
            if (isFixedTable) {
                if (fixedSelectedIndex != -1) {
                    dataTable.setRowSelectionInterval(fixedSelectedIndex, fixedSelectedIndex);
                } else {
                    if (selectedIndex != -1) {
                        fixedTable.setRowSelectionInterval(selectedIndex, selectedIndex);
                    }
                }

            } else {
                if (selectedIndex != -1) {
                    fixedTable.setRowSelectionInterval(selectedIndex, selectedIndex);
                }
            }
        }
    }

    /*
     * Refresh the scrolling panel
     */
    private void fixScrollUI() {
        if (tableLoader.getFixedColSize() > 0) {
            fixedTable.clearSelection();
            viewport.setView(fixedTable);
            viewport.setPreferredSize(fixedTable.getPreferredSize());
            scroll.setRowHeaderView(viewport);
            tableLoader.getTask().onloaded();
        }
        ((DyAbstractTableModel) tableLoader.getNormalModel()).fireTableStructureChanged();
        scroll.setViewportView(dataTable);
        if (tableLoader.getFlag() == DyTableLoader.COL) {
            allResizeTable(true);
        }
        scroll.updateUI();
    }

    /*
    Sliding forward scroll bar, perform a task,
    load the data, update the position of the scroll bar
     */
    private class NextTask extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() throws Exception {
            enable = false;
            final int sleepTime = 500;
            Thread.sleep(sleepTime);
            tableLoader.nextBatch();
            return null;
        }

        @Override
        protected void done() {
            scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
            fixScrollUI();
            JScrollBar bar;
            if (tableLoader.getFlag() == DyTableLoader.ROW) {
                bar = (JScrollBar) scroll.getVerticalScrollBar();
                int value = bar.getValue();
                final int rowHight = 16;
                if (tableLoader.getPageNumber() > 2 && tableLoader.getPageNumber() != tableLoader.getPageCount()) {
                    bar.setValue(value - rowHight * tableLoader.getPageSize());
                }
            } else if (tableLoader.getFlag() == DyTableLoader.COL) {
                bar = (JScrollBar) scroll.getHorizontalScrollBar();
                bar.setMaximum(maximum);
                if (tableLoader.getPageNumber() != tableLoader.getPageCount()) {
                    final int distance = 10;
                    bar.setValue(distance);
                }
            }
            enable = true;
        }
    }

    /*
    Sliding Backward scroll bar, perform a task,
    load the data, update the position of the scroll bar
     */
    private class PreTask extends SwingWorker<Void, Void> {

        @Override
        protected Void doInBackground() throws Exception {
            enable = false;
            final int sleepTime = 500;
            Thread.sleep(sleepTime);
            tableLoader.preBatch();
            return null;
        }

        @Override
        protected void done() {
            scroll.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
            fixScrollUI();
            JScrollBar bar;
            if (tableLoader.getFlag() == DyTableLoader.ROW) {
                bar = (JScrollBar) scroll.getVerticalScrollBar();
                int value = bar.getValue();
                final int rowHight = 16;
                if (tableLoader.getPageNumber() > 1) {
                    bar.setValue(value + rowHight * tableLoader.getPageSize());
                }
            } else if (tableLoader.getFlag() == DyTableLoader.COL) {
                bar = (JScrollBar) scroll.getHorizontalScrollBar();
                bar.setMaximum(maximum);
                int extent = bar.getModel().getExtent();
                int max = bar.getMaximum();
                if (tableLoader.getPageNumber() != 1) {
                    final int distance = 10;
                    bar.setValue(max - (extent + distance));
                }
            }
            enable = true;
        }
    }

    public JTable getFixedTable() {
        return fixedTable;
    }

    public void setDataTable(JTable dataTable) {
        this.dataTable = dataTable;
    }

    public JTable getDataTable() {
        return dataTable;
    }

    public JScrollPane getScroll() {
        return scroll;
    }

    private JTable fixedTable;
    private JTable dataTable;
    private JScrollPane scroll;
    private JViewport viewport;


}
